#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <string.h>

#define WIDTH 50
#define HEIGHT 20

int map[HEIGHT][WIDTH];
int snakeX[100], snakeY[100];
int foodX, foodY;
int score = 0;
int highScore = 0;
int snakeLength = 1;
int direction = 1; // 1: 右, 2: 下, 3: 左, 4: 上
int gameOver = 0;

int speed = 200; // 初始速度
// 函数原型声明
void gotoxy(int x, int y);
void printsnake();
void welcometogame();
void createMap();
void displayHighScore();
void initsnake();
void createfood();
void speedup();
void speeddown();
void snakemove();
void endGame();
void resetGame();
void showInstructions();


void gotoxy(int x, int y) {
    COORD coord;
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

void printsnake() {
    system("cls");
    printf("\n\n");
    printf("    ###########    ###########    ###########\n");
    printf("    ###########    ###########    ###########\n");
    printf("    ###########    ###########    ###########\n");
    printf("    #####贪####    ####吃#####    #####蛇####\n");
    printf("    ###########    ###########    ###########\n");
    printf("    ###########    ###########    ###########\n");
    printf("    ###########    ###########    ###########\n");
    printf("\n\n");
    printf("        1. 开始游戏\n");
    printf("        2. 最高分数\n");
    printf("        3. 退出游戏\n");
    printf("        4. 游戏帮助\n");
}

void welcometogame() {
    printsnake();
    while (1) {
        if (_kbhit()) {
            char ch = _getch();
            if (ch == '1') {
                createMap();
                initsnake();
                createfood();
                snakemove();
                break;
            } else if (ch == '2') {
                displayHighScore();
            } else if (ch == '3') {
                exit(0);
            }else if (ch == '4') {
                showInstructions();
            }
        }
    }
}

void createMap() {
    system("cls");
    for (int i = 0; i < WIDTH + 2; i++) {
        printf("#");
    }
    printf("\n");
    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            map[i][j] = 0;
            if (j == 0 || j == WIDTH - 1) {
                printf("#");
            } else {
                printf(" ");
            }
        }
        printf("#\n");
    }
    for (int i = 0; i < WIDTH + 2; i++) {
        printf("#");
    }
    printf("\n");
    printf("当前分数: %d | 最高分数: %d\n", score, highScore);
}

void displayHighScore() {
    system("cls");
    FILE *file = fopen("save.txt", "r");
    if (file != NULL) {
        fscanf(file, "%d", &highScore);
        fclose(file);
    }
    printf("最高分数: %d\n", highScore);
    printf("按任意键返回...\n");
    _getch();
    welcometogame();
}

void initsnake() {
    snakeX[0] = WIDTH / 2;
    snakeY[0] = HEIGHT / 2;
    for (int i = 1; i < snakeLength; i++) {
        snakeX[i] = snakeX[i - 1] - 1;
        snakeY[i] = snakeY[i - 1];
    }
}

void createfood() {
    int valid = 0;
    while (!valid) {
        foodX = rand() % (WIDTH - 2) + 1;
        foodY = rand() % (HEIGHT - 2) + 1;
        valid = 1;
        for (int i = 0; i < snakeLength; i++) {
            if (snakeX[i] == foodX && snakeY[i] == foodY) {
                valid = 0;
                break;
            }
        }
    }
}

void speedup() {
    if (speed > 10) {
        speed -= 10;
    }
}

void speeddown() {
    speed += 30;
}

void snakemove() {
    int prevX, prevY;
    prevX = snakeX[0];
    prevY = snakeY[0];

    // 通过方向键更新蛇头位置
    if (direction == 1) {
        snakeX[0]++;
    } else if (direction == 2) {
        snakeY[0]++;
    } else if (direction == 3) {
        snakeX[0]--;
    } else if (direction == 4) {
        snakeY[0]--;
    }

    // 检测是否撞到边界
    if (snakeX[0] <= 0 || snakeX[0] >= WIDTH - 1 || snakeY[0] <= 0 || snakeY[0] >= HEIGHT - 1) {
        gameOver = 1;
    }

    // 检测是否撞到蛇身
    for (int i = 1; i < snakeLength; i++) {
        if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
            gameOver = 1;
            break;
        }
    }

    // 检测是否吃到食物
    if (snakeX[0] == foodX && snakeY[0] == foodY) {
        score += 2;
        snakeLength++;
        createfood();
        speedup();
    } else {
        // 移动剩余蛇身
        for (int i = 1; i < snakeLength; i++) {
            int tempX = snakeX[i];
            int tempY = snakeY[i];
            snakeX[i] = prevX;
            snakeY[i] = prevY;
            prevX = tempX;
            prevY = tempY;
        }
    }

    // 绘制蟒蛇和食物
    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            map[i][j] = 0;
        }
    }
    for (int i = 0; i < snakeLength; i++) {
        map[snakeY[i]][snakeX[i]] = 1;
    }
    map[foodY][foodX] = 2;

    system("cls");
    printf("Score: %d | Highest Score: %d | Speed: %d\n", score, highScore, speed);
    // 绘制上边界
    for (int i = 0; i < WIDTH + 2; i++) {
        printf("#");
    }
    printf("\n");
    
    // 获得句柄以控制蟒蛇与食物颜色
    HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);

    for (int i = 0; i < HEIGHT; i++) {
        printf("#");
        for (int j = 0; j < WIDTH; j++) {
            if (map[i][j] == 1) {
                SetConsoleTextAttribute(console, 14); // 令蟒蛇为黄色
                printf("*");
                SetConsoleTextAttribute(console, 15); // 重置为默认颜色
            } else if (map[i][j] == 2) {
                SetConsoleTextAttribute(console, 10); // 令食物为绿色
                printf("O");
                SetConsoleTextAttribute(console, 15); // 重置为默认颜色
            } else {
                printf(" ");
            }
        }
        printf("#\n");
    }

// 绘制下边界
    for (int i = 0; i < WIDTH + 2; i++) {
        printf("#");
    }
    printf("\n");
    
    // 检测游戏是否结束
    if (gameOver) {
        endGame();
    }

    // 检测键盘输入以改变方向
    if (_kbhit()) {
        char ch = _getch();
        if (ch == 'w' && direction != 2) direction = 4;
        else if (ch == 's' && direction != 4) direction = 2;
        else if (ch == 'a' && direction != 1) direction = 3;
        else if (ch == 'd' && direction != 3) direction = 1;
        // 使用GetAsyncKeyState来实现用F1，F2来加速和减速
        else if (GetAsyncKeyState(VK_F1)) { // F1控制加速并得分
            speedup();
            score += 2;
        }
        else if (GetAsyncKeyState(VK_F2)) { // F2控制减速并扣分
            speeddown();
            score -= 2;
            if (score < 0) score = 0; // 保证得分不为负数
        }
        // 按ESC结束游戏
        else if (ch == '\x1B') { // ESC键控制游戏结束
            gameOver = 1;
        }
    }

    Sleep(speed);
    snakemove();
}
void endGame() {
    system("cls");
    printf("游戏结束!\n");
    printf("你的得分: %d\n", score);
    if (score > highScore) {
        highScore = score;
        FILE *file = fopen("save.txt", "w");
        fprintf(file, "%d", highScore);
        fclose(file);
        printf("创纪录啦！最高分被你刷新啦，真棒！！！\n");
    } else {
        printf("最高分数: %d\n", highScore);
    }
    printf("按 1 重新开始游戏 或按 2 退出游戏\n");
    char ch = _getch();
    if (ch == '1') {
        resetGame();
        welcometogame();
    } else if (ch == '2') {
        exit(0);
    } else {
        printf("输入错误，重新选择： 按 1 重新开始游戏 或按 2 退出游戏\n");
        _getch();
    }
}

//重置游戏设置
void resetGame() {
    score = 0;
    snakeLength = 1;
    direction = 1;
    gameOver = 0;
    speed = 200;
}

// 游戏规则界面设置
void showInstructions() {
    system("cls");
    printf("游戏帮助:\n");
    printf("=====================\n");
    printf("贪吃蛇游戏是一款老少皆宜，深受人们喜爱的小游戏。\n");
    printf("在我们的游戏中，你将成为一条年幼的蟒蛇，在危机重重的亚马逊丛林中寻找新鲜美味儿的水果（fruit），吃下它，并逐渐成长为一条真正的蟒（man）蛇王。\n");
    printf("规则如下：\n");
    printf("1.使用'w''a''s''d'实现上下左右移动。\n");
    printf("2.当你吃下水果后，你的速度会变快。\n");
    printf("3.使用’F1‘可以实现加速并得分+2；使用’F2‘可以实现减速并得分-2。\n");
    printf("4.当你触碰到游戏边界或者咬到自己时，游戏结束，你也可以通过在游戏中使用’esc‘键来结束游戏。\n");
    printf("=====================\n");
    printf("最后，希望你能玩得开心，谢谢你玩我们的游戏。\n");
    printf("\n");
    printf("by郝煜坤and梁文麒\n");
    printf("按任意键返回...\n");
    _getch();
    welcometogame();
}

int main() {
    srand(time(0));
    welcometogame();
    return 0;
}